#include "StdAfx.h"
#include "Williams2Machine.h"

CWilliams2Machine::CWilliams2Machine()
{
ChangeLoadInfo(ROM_CPU1,MainROM2);
AddLoadInfo(ROM_VROM1,VROM);
}

CWilliams2Machine::~CWilliams2Machine()
{
}

int CWilliams2Machine::Init()
{
CWilliamsMachine::Init();
MainCPU->SetOp(ReadMainCPU);
MainCPU->SetRead(ReadMainCPU);
MainCPU->SetWrite(WriteMainCPU);

PIA[0]->Init();			//clear all function pointers
PIA[1]->Init();
PIA[2]->Init();

PIA[0]->InputAFunc = PIA0_InputA_Mux;			//defined in CWilliamsMachine
PIA[0]->InputBFunc = PIA0_InputB;				//defined in CDefenderMachine
PIA[0]->OutputCA2Func = PIA0_OutputCB2_Mux;	//defined in CWilliamsMachine

PIA[1]->InputAFunc = PIA1_InputA;				//defined in CDefenderMachine
PIA[1]->OutputBFunc = PIA1_OutputB;
PIA[1]->OutputCB2Func = PIA1_OutputCB2;
PIA[1]->IRQAFunc = PIA1_IRQA;						//defined in CDefenderMachine
PIA[1]->IRQBFunc = PIA1_IRQB;						//defined in CDefenderMachine

PIA[2]->OutputAFunc = CWilliams2Machine::PIA2_OutputA;
PIA[2]->OutputBFunc = CDefenderMachine::PIA2_OutputA;
PIA[2]->OutputCA2Func = CWilliams2Machine::PIA2_OutputCA2;
PIA[2]->IRQAFunc = PIA2_IRQA;						//defined in CDefenderMachine
PIA[2]->IRQBFunc = PIA2_IRQB;						//defined in CDefenderMachine

return(0);
}

void CWilliams2Machine::Reset()
{
CWilliamsMachine::Reset();
}

void CWilliams2Machine::Line(u32 mainc,u32 soundc,int irq)
{
CWilliamsMachine::Line(mainc,soundc,irq);
}

void CWilliams2Machine::SaveState(CState *s)
{
CWilliamsMachine::SaveState(s);
}

void CWilliams2Machine::LoadState(CState *s)
{
CWilliamsMachine::LoadState(s);
}

u8 CWilliams2Machine::ReadMainCPU(void *user,u32 addr)
{
CWilliams2Machine *M = (CWilliams2Machine*)user;

switch(addr & 0xF000)
	{
	case 0x0000:
	case 0x1000:
	case 0x2000:
	case 0x3000:
	case 0x4000:
	case 0x5000:
	case 0x6000:
	case 0x7000:
		return(M->BankPointer[addr]);
	case 0x8000:
	case 0x9000:
		if(addr >= 0x9800)
			return(M->MainRAM[addr - 0x9800]);
		return(M->BankPointer[addr]);
	case 0xA000:
	case 0xB000:
		return(M->MainRAM[addr - 0x9800]);
	case 0xC000:
		if(addr < 0xC800)							//tile ram
			return(M->TileRAM[addr & 0x7FF]);
		if(addr >= 0xCC00)						//nvram
			return(M->NVRAM[addr & 0x3FF]);
		if(addr >= 0xCBE0)
			{
			if(M->Scanline > 0xFF)
				return(0xFF);
			return((u8)M->Scanline);
			}
		if(addr >= 0xC980 && addr <= 0xC988)
			{
			if(addr & 4)				//pia 1 read
				return(M->PIA[1]->Read(addr & 3));
			else							//pia 0 read
				return(M->PIA[0]->Read(addr & 3));
			}
		break;
	case 0xD000:
		if(M->RomSet->GetFlags() & F_BONUSRAM)
			return(M->BonusRAM[addr & 0xFFF]);
	case 0xE000:
	case 0xF000:
		return(M->MainROM2[addr]);
	}
message("unhandled read (main cpu, addr $%04X)\n",addr);
return(0);
}

void CWilliams2Machine::WriteMainCPU(void *user,u32 addr,u8 data)
{
CWilliams2Machine *M = (CWilliams2Machine*)user;

switch(addr & 0xF000)
	{
	case 0x0000:
	case 0x1000:
	case 0x2000:
	case 0x3000:
	case 0x4000:
	case 0x5000:
	case 0x6000:
	case 0x7000:
	case 0x8000:
		M->VRAM[addr] = data;
		return;
	case 0x9000:
		if(addr < 0x9800)
			{
			M->VRAM[addr] = data;
			return;
			}
	case 0xA000:
	case 0xB000:
		M->MainRAM[addr - 0x9800] = data;
		return;
	case 0xC000:								//palette/nvram/io
		if(addr < 0xC800)							//tile ram
			{
			M->TileRAM[addr & 0x7FF] = data;
			return;
			}
		if(addr >= 0xCC00)						//nvram
			{
			M->NVRAM[addr & 0x3FF] = data;
			return;
			}
		if(addr >= 0xC980 && addr <= 0xC988)
			{
//	AM_RANGE(0xc980, 0xc983) AM_MIRROR(0x0070) AM_READWRITE(pia_1_r, pia_1_w)
//	AM_RANGE(0xc984, 0xc987) AM_MIRROR(0x0070) AM_READWRITE(pia_0_r, pia_0_w)
//	AM_RANGE(0xc98c, 0xc98f) AM_MIRROR(0x0070) AM_WRITE(williams2_7segment_w)
			if(addr & 4)
				M->PIA[1]->Write(addr & 3,data);
			else
				M->PIA[0]->Write(addr & 3,data);
			return;
			}
		if(addr < 0xC880)
			{
			//AM_WRITE(williams2_bank_select_w)
			message("bank select = $%02X\n",data);
			switch(data & 3)
				{
				case 0:			//vram
					M->BankPointer = M->VRAM;
					return;
				case 1:			//rom 0
					M->BankPointer = M->MainROM2 + 0x10000 + ((data & 4) << 14);
					return;
				case 2:			//rom 1
					M->BankPointer = M->MainROM2 + 0x30000 + ((data & 4) << 14);
					return;
				case 3:			//palette
					M->BankPointer = M->MainROM2 + 0x10000 + ((data & 4) << 14);
					return;
				}
			return;
			}
		if(addr < 0xC900)
			{
			switch(addr & 7)
				{
				case 0:	M->ExecuteBlit(data);			return;
				case 1:	M->BlitterMask = data;			return;
				case 2:	M->BlitterSrcHi = data;			return;
				case 3:	M->BlitterSrcLo = data;			return;
				case 4:	M->BlitterDestHi = data;		return;
				case 5:	M->BlitterDestLo = data;		return;
				case 6:	M->BlitterHeight = data;		return;
				case 7:	M->BlitterWidth = data;			return;
				}
			return;
			}
		if(addr < 0xC980)
			{
			if((data & 0x3F) == 0x14)
				M->Watchdog->Write(W_CPU1);
			return;
			}
		if(addr >= 0xC98C && addr <= 0xC98F)
			{
			//from mame
			int n;
			char dot;

			switch(data & 0x7F)
				{
				case 0x40:	n = 0; break;
				case 0x79:	n = 1; break;
				case 0x24:	n = 2; break;
				case 0x30:	n = 3; break;
				case 0x19:	n = 4; break;
				case 0x12:	n = 5; break;
				case 0x02:	n = 6; break;
				case 0x03:	n = 6; break;
				case 0x78:	n = 7; break;
				case 0x00:	n = 8; break;
				case 0x18:	n = 9; break;
				case 0x10:	n = 9; break;
				default:	n = -1; break;
				}
			if((data & 0x80) == 0x00)
				dot = '.';
			else
				dot = ' ';
			if(n == -1)
				message("LED: [ %c]\n",dot);
			else
				message("LED: [%d%c]\n",n,dot);
			return;
			}
		if(addr >= 0xCBE0)
			{
			//nothing
			return;
			}
		if(addr >= 0xCBC0)
			{
			//nothing
			return;
			}
		if(addr >= 0xCBA0)
			{
			//AM_WRITE(williams2_blit_window_enable_w)
			message("williams2_blit_window_enable_w\n");
			return;
			}
		if(addr >= 0xCB80)
			{
			//AM_WRITE(defender_video_control_w)
			message("defender_video_control_w\n");
			return;
			}
		if(addr >= 0xCB60)
			{
			//AM_WRITE(williams2_xscroll_high_w)
			message("williams2_xscroll_high_w\n");
			return;
			}
		if(addr >= 0xCB40)
			{
			//AM_WRITE(williams2_xscroll_low_w)
			message("williams2_xscroll_low_w\n");
			return;
			}
		if(addr >= 0xCB20)
			{
			//AM_WRITE(williams2_bg_select_w)
			message("williams2_bg_select_w\n");
			return;
			}
		if(addr >= 0xCB00)
			{
			//AM_WRITE(williams2_fg_select_w)
			message("williams2_fg_select_w\n");
			return;
			}
		message("unhandled io write (main cpu, addr $%04X = $%02X)\n",addr,data);
		return;
	case 0xD000:
		if(M->RomSet->GetFlags() & F_BONUSRAM)
			{
			M->BonusRAM[addr & 0xFFF] = data;
			return;
			}
	default:
		message("unhandled write (main cpu, addr $%04X = $%02X)\n",addr,data);
		return;
	}
}

#if 0
/* Generic muxing PIA 0, maps to input ports 0/3 and 1; port select is CA2 */
const pia6821_interface williams2_muxed_pia_0_intf =
{
	/*inputs : A/B,CA/B1,CA/B2 */ williams_input_port_0_3_r, input_port_1_r, 0, 0, 0, 0,
	/*outputs: A/B,CA/B2       */ 0, 0, williams_port_select_w, 0,
	/*irqs   : A/B             */ 0, 0
};
/* Generic PIA 1, maps to input port 2, sound command out, and IRQs */
const pia6821_interface williams2_pia_1_intf =
{
	/*inputs : A/B,CA/B1,CA/B2 */ input_port_2_r, 0, 0, 0, 0, 0,
	/*outputs: A/B,CA/B2       */ 0, williams2_snd_cmd_w, 0, pia_2_ca1_w,
	/*irqs   : A/B             */ williams_main_irq, williams_main_irq
};
/* Generic PIA 2, maps to DAC data in and sound IRQs */
const pia6821_interface williams2_snd_pia_intf =
{
	/*inputs : A/B,CA/B1,CA/B2 */ 0, 0, 0, 0, 0, 0,
	/*outputs: A/B,CA/B2       */ pia_1_portb_w, DAC_0_data_w, pia_1_cb1_w, 0,
	/*irqs   : A/B             */ williams_snd_irq, williams_snd_irq
};

PIA[0]->InputAFunc = PIA0_InputA_Mux;			//defined in CWilliamsMachine
PIA[0]->InputBFunc = PIA0_InputB;				//defined in CDefenderMachine
PIA[0]->OutputCA2Func = PIA0_OutputCB2_Mux;	//defined in CWilliamsMachine

PIA[1]->InputAFunc = PIA1_InputA;				//defined in CDefenderMachine
PIA[1]->OutputBFunc = PIA1_OutputB;
PIA[1]->OutputCB2Func = PIA1_OutputCB2;
PIA[1]->IRQAFunc = PIA1_IRQA;						//defined in CDefenderMachine
PIA[1]->IRQBFunc = PIA1_IRQB;						//defined in CDefenderMachine

PIA[2]->OutputAFunc = CWilliams2Machine::PIA2_OutputA;
PIA[2]->OutputBFunc = CDefenderMachine::PIA2_OutputA;
PIA[2]->OutputCA2Func = CWilliams2Machine::PIA2_OutputCA2;
PIA[2]->IRQAFunc = PIA2_IRQA;
PIA[2]->IRQBFunc = PIA2_IRQB;

#endif

//CONFIGURE_PIAS(williams2_muxed_pia_0_intf, joust2_pia_1_intf, williams2_snd_pia_intf);

void CWilliams2Machine::PIA1_OutputB(void *user,u8 data)
{
CWilliams2Machine *M = (CWilliams2Machine*)user;

M->SoundWrites.add((void*)(u32)(data | 0x100C0));	//add this write to the write queue
}

void CWilliams2Machine::PIA1_OutputCB2(void *user,u8 data)
{
CWilliams2Machine *M = (CWilliams2Machine*)user;

M->PIA[2]->set_input_ca1(data);
}

void CWilliams2Machine::PIA2_OutputA(void *user,u8 data)
{
CWilliams2Machine *M = (CWilliams2Machine*)user;

M->PIA[1]->SetInputB(data);
}

void CWilliams2Machine::PIA2_OutputCA2(void *user,u8 data)
{
CWilliams2Machine *M = (CWilliams2Machine*)user;

M->PIA[1]->set_input_cb1(data);
}
